package game.objects.nonstaticObjects;

import engine.Engine;
import engine.game.Manager;
import engine.graphics.FontManager;
import engine.graphics.Vertex2f;
import engine.objects.ObjectInspector;
import engine.objects.PhysicsObject;
import engine.objects.TexturedObject;
import engine.system.EDirection;
import engine.system.ID;
import game.entity.Entity;
import game.objects.staticObjects.BottomOfTheWorld;

public class EntityModel extends PhysicsObject{

	private static final long serialVersionUID = 1L;
	
	public static final String MOVING_LEFT = "left", 
							   MOVING_RIGHT = "right", 
							   STANDING_STILL = "standing",
							   STANDING_STILL_LEFT = "standingLeft",
							   STANDING_STILL_RIGHT = "standingRight"; 
	
	private final Entity entity ; 
	private ItemModel[] inventory  ; 
	private boolean pickedUpNewItem = false ;
	private ItemModel latestPickedUp = null ; 
	
	private boolean isCrouching = false ;
	private boolean isMovingLeft = false ; 
	private boolean isMovingRight = false ;
	
	private boolean ropeEnabled = false ; 
	
	private Rope rope ;

	private boolean standingInAccordanceToMovingDirection = false;

	public EntityModel(Manager m, int x, int y, int w, int h, Entity e) {
		this(m, x, y, w, h, true, e);
	}
	public EntityModel(Manager m, int x, int y, int w, int h, boolean collidable, Entity e) {
		super(m, x, y, w, h, collidable);
		this.entity = e ; 
		this.setSpeed(this.entity.getAttributes().getSpeed());
		init(); 
	}
	
	public void init(){
		this.inventory = new ItemModel[Entity.INVENTORY_SIZE] ; 
	}
	
	public Vertex2f getPosition(){
		float x = (float) getCenterX(); 
		float y = (float) getCenterY();
		return new Vertex2f(x, y); 
	}
		
	public Entity getEntity(){
		return this.entity ; 
	}
	
	public ItemModel[] getInventory(){
		return this.inventory; 
	}
	
	public boolean hasPickedUpNewItem(){
		boolean tmp = this.pickedUpNewItem;
		if(tmp)
			this.pickedUpNewItem = false ;
		return tmp ; 
	}
	
	public ItemModel getLatetstPickedUp(){
		return this.latestPickedUp; 
	}
	
	public boolean ropeShot(){
		return (rope != null) ; 
	}
	
	public void enableCrouching(){
		this.isCrouching = true ; 
	}
	
	public void disableCrouching(){
		this.isCrouching = false ; 
	}
	
	public boolean isCrouching(){
		return this.isCrouching; 
	}
	
	public boolean isMovingLeft(){
		return this.isMovingLeft; 
	}
	
	public boolean isMovingRight(){
		return this.isMovingRight ; 
	}
	
	public void enableRope(){
		this.ropeEnabled = true ; 
	}
	
	public void disableRope(){
		this.ropeEnabled = false ; 
	}
	
	public boolean ropeEnabled(){
		return this.ropeEnabled; 
	}

	public void shootRope(Vertex2f end){
		if(this.ropeEnabled())
			this.rope = new Rope(this, (float)getCenterX(), (float)getCenterY(), 
							end.getX(), end.getY()) ; 
	}
	
	public void releaseRope(){
		rope = null ; 
	}

//	public boolean collisionCriteriaGiven(){
//		return this.getObjectCollision().isColliding() && 
//					!ObjectInspector.isInstance(this.getObjectCollision().getObject(), ItemModel.class);
//	}
	
	public void jump(){
		if(ropeShot())
			this.moveByDelta(new Vertex2f(rope.getShootingVelocity().getX() / (this.getSpeed()*3),
									rope.getShootingVelocity().getY() / (this.getSpeed()*3))) ; 
		else{
			super.jump(); 
		}
	}
	
	public void crouch(){
		if(this.isJumping() || this.isFalling())
			this.disableCrouching() ; 
		else{
			if(this.isCrouching()){
				this.setBounds(getX(), getY(), this.ORIGINAL_WIDTH, this.ORIGINAL_HEIGHT / 2);
				this.disableCrouching(); 
			}else {
				this.setBounds(getX(), getY(), this.ORIGINAL_WIDTH, this.ORIGINAL_HEIGHT);
//				this.changeTexture("left"); 
			}
		}
	}

	public void die(){
		this.disableUpdating(); 
		this.stopAllTimers(); 
		this.entity.die(); 
	}
	
	public void update(){
		this.entity.update(); 
		if(this.entity.isDead())
			this.getManager().remove(this);
		if(ropeShot()){
			rope.update(); 
			this.disableFalling(); 
		}
		super.update(); 
		this.crouch(); 
		if(this.hasObjectCollision() && (ObjectInspector.isInstance(this.objectCollision.getObject(), ItemModel.class)))
			this.pickUp((ItemModel)ObjectInspector.getInstance(this.objectCollision.getObject(), ItemModel.class)); 
		else if(this.hasObjectCollision() && (ObjectInspector.isInstance(this.objectCollision.getObject(), BottomOfTheWorld.class)))
			this.die(); 
		if(standingInAccordanceToMovingDirection()){
			if(this.isMovingLeft())
				this.changeAnimation(STANDING_STILL_LEFT);
			else if(this.isMovingRight())
				this.changeAnimation(STANDING_STILL_RIGHT);
		}else
			this.changeAnimation(STANDING_STILL);
	}
	
	private boolean standingInAccordanceToMovingDirection() {
		return standingInAccordanceToMovingDirection ;
	}
	public void move(EDirection dir){
		if(!ropeShot())
			super.move(dir); 
	}
	
	protected void moveLeft(int speed){
		this.changeAnimation(MOVING_LEFT);
		this.isMovingLeft = true ; 
		this.isMovingRight = false ; 
		super.moveLeft(speed);
	}
	
	protected void moveRight(int speed){
		this.changeAnimation(MOVING_RIGHT);
		this.isMovingRight = true ; 
		this.isMovingLeft = false ; 
		super.moveRight(speed);
	}
	
	public int getIDOfFirstFreeInventorySlot(){
		for(int i=0; i<this.inventory.length; i++)
			if(this.inventory[i] == null) 
				return i ; 
		return -1 ; 
	}
	
	public void pickUp(ItemModel item){
		if(this.getIDOfFirstFreeInventorySlot() != -1){
			this.inventory[this.getIDOfFirstFreeInventorySlot()] = item;
			if(item.getItem().hasDirectEffect())
				item.getItem().releaseEffectOn(this.entity) ; 
			item.pickUp(this);
			this.pickedUpNewItem = true ; 
			this.latestPickedUp = item ; 
		}
	}
	
	public void dropItem(int itemID){
		ItemModel item = this.inventory[itemID]; 
		if(item != null){
			if(item.getItem().hasReleasedEffect() && item.getItem().hasDirectEffect())
				item.getItem().invertEffectOn(this.entity);
			if(item.getItem().hasDirectEffect() || 
					(!item.getItem().hasDirectEffect() && !item.getItem().hasReleasedEffect()))
				item.drop(); 
			this.inventory[itemID] = null;
		}
	}
	
	public void render(){
		super.render(); 
		String fontName = FontManager.S_FONT_11 ; 
		int x = (int)this.getMinX(); 
		int y = Engine.HEIGHT-(int)this.getMaxY();
		FontManager.drawString(fontName, x,y-65, this.entity.getAttributes().toString());
		if(ropeShot())
			rope.render(); 
	}

	public static void loadEntityAnimations(EntityModel o, Class<?> clazz){
		int WIDTH = o.getObjectWidth();
		int HEIGHT = o.getObjectHeight();
		String name = clazz.getSimpleName().toLowerCase();
		TexturedObject.addNewAnimationToObject(o, EntityModel.MOVING_LEFT, name , 
				WIDTH, HEIGHT, new ID[]{new ID(0,1), new ID(1,1), new ID(2,1), new ID(3,1)}, 150); 
		TexturedObject.addNewAnimationToObject(o, EntityModel.MOVING_RIGHT, name,
				WIDTH, HEIGHT, new ID[]{new ID(0,2), new ID(1,2), new ID(2,2), new ID(3,2)}, 150); 
		TexturedObject.addNewAnimationToObject(o, EntityModel.STANDING_STILL, name,
				WIDTH, HEIGHT, new ID[]{new ID(0,0), new ID(1,0), new ID(2,0), new ID(3,0)}, 150);
		
	}
	
}
